﻿using System;
using System.Text;
using System.Collections.Generic;
using System.Linq;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using BeanboxSoftware.BeanMap;
using System.Reflection;

namespace BeanboxSoftware.BeanMapTest.Generics
{
  [TestClass]
  public class MapKKVTest
  {
    [TestMethod]
    public void BasicUseTest()
    {
      var map = new Map<int, double, string>();

      map[4, 4.1] = "4, 4.1";

      Assert.AreEqual("4, 4.1", map[4, 4.1], "4, 4.1");
    }

    [TestMethod]
    public void ListCtorTest()
    {
      var values = new List<string>();
      values.Add("1.3");
      values.Add("2.3");
      values.Add("3.3");

      var map = new Map<int, double, string>(values, v => (int)double.Parse(v), v => double.Parse(v));

      Assert.AreEqual("1.3", map[1, 1.3], "1.3");
      Assert.AreEqual("2.3", map[2, 2.3], "2.3");
      Assert.AreEqual("3.3", map[3, 3.3], "3.3");
    }

    [TestMethod]
    public void KeyValuesTest()
    {
      var map = new Map<int, double, string>();
      map[10, 3.2] = "the hive";

      var kvs = map.KeyValues;

      Assert.AreEqual(10, kvs.First().Key.Item1, "key 1");
      Assert.AreEqual(3.2, kvs.First().Key.Item2, "key 2");
      Assert.AreEqual("the hive", kvs.First().Value, "value");
    }

    [TestMethod]
    public void DefaultGenerationTest()
    {
      var map = new Map<int, double, string>();

      map.DefaultGeneration = (i, d) => string.Format("{0}, {1}", i.ToString(), d.ToString());

      Assert.AreEqual("4, 3.2", map[4, 3.2], "default two key gen");
    }

    [TestMethod]
    public void RemoveTest()
    {
      var map = new Map<int, double, string>();
      map[1, 1.1] = "1, 1.1";

      Assert.IsTrue(map.ContainsKey(1, 1.1), "contains key before remove");
      Assert.IsFalse(map.Remove(1, 1.2), "removing nonexistent keys 1");
      Assert.IsFalse(map.Remove(2, 1.2), "removing nonexistent keys 2");
      Assert.IsTrue(map.Remove(1, 1.1), "removing existent keys");
      Assert.IsFalse(map.ContainsKey(1, 1.1), "contains key after remove");
    }

    [TestMethod]
    public void ContainsKeyTest()
    {
      var map = new Map<int, double, string>();
      map[1, 2.3] = "1, 2.3";

      Assert.IsTrue(map.ContainsKey(1, 2.3), "contains 1, 2.3");
      Assert.IsFalse(map.ContainsKey(1, 2.4), "contains 1, 2.4");

      TestUtils.AssertExceptionThrown<KeyNotFoundException>(() => { var result = map[1, 2.4]; });
    }

    [TestMethod]
    public void ChildTest()
    {
      var cache = new Map<Type, long, object>();

      cache[typeof(string), 0] = "a";
      cache[typeof(string), 1] = "b";

      var strings = cache[typeof(string)];
      strings[2] = "c";

      Assert.AreEqual("c", cache[typeof(string), 2], "cache at string 2");

      Assert.IsNotNull(cache[typeof(int)], "cache at int");

      var ints = new Map<long, object>();
      ints[0] = 0;
      ints[1] = 1;

      Assert.IsFalse(cache.ContainsKey(typeof(int)), "cache contains int");
    }

    [TestMethod]
    public void CopyCtor()
    {
      var map = new Map<int, int, string>();
      map[10, 1] = "10";
      map[15, 1] = "15";

      var copy = new Map<int, int, string>(map);

      Assert.AreEqual(map[10, 1], copy[10, 1], "10, 1");
      Assert.AreEqual(map[15, 1], copy[15, 1], "15, 1");

      copy[20, 2] = "20";
      map.Remove(10, 1);

      Assert.IsFalse(map.ContainsKey(20, 2), "20");
      Assert.IsTrue(copy.ContainsKey(10, 1), "10");
    }

    class Thing
    {
      public int Foo { get; set; }
      public int Bar { get; set; }
      public string Baz { get; set; }
    }

    [TestMethod]
    public void ListToMapTest()
    {
      var things = new List<Thing>
                 {
                     new Thing {Foo = 3, Bar = 3, Baz = "quick"},
                     new Thing {Foo = 3, Bar = 4, Baz = "brown"},
                     new Thing {Foo = 6, Bar = 3, Baz = "fox"},
                     new Thing {Foo = 6, Bar = 4, Baz = "jumps"}
                 };

      var thingMap = Map<int, int, string>.From(things, t => t.Foo, t => t.Bar, t => t.Baz);

      Assert.IsTrue(thingMap.ContainsKey(3, 4));
      Assert.AreEqual("brown", thingMap[3, 4]);

      thingMap.DefaultValue = string.Empty;
      Assert.AreEqual("brown", thingMap[3, 4]);
      Assert.AreEqual(string.Empty, thingMap[3, 6]);
      Assert.IsFalse(thingMap.ContainsKey(3, 6));

      thingMap.DefaultGeneration = (k1, k2) => (k1.ToString() + k2.ToString());

      Assert.IsFalse(thingMap.ContainsKey(3, 6));
      Assert.AreEqual("36", thingMap[3, 6]);
      Assert.IsTrue(thingMap.ContainsKey(3, 6));
    }
  }
}
